
// AnalyticDrawingView.cpp : implementation of the CAnalyticDrawingView class
//

#include "stdafx.h"
// SHARED_HANDLERS can be defined in an ATL project implementing preview, thumbnail
// and search filter handlers and allows sharing of document code with that project.
#ifndef SHARED_HANDLERS
#include "AnalyticDrawing.h"
#endif

#include "AnalyticDrawingDoc.h"
#include "AnalyticDrawingView.h"

#include "display/OpenGLDisplay.h"

#include "MainFrm.h"

//	for debugging
#include <iostream>
#include <fstream>
using namespace std;

#ifdef _DEBUG
#define new DEBUG_NEW
#endif

// CAnalyticDrawingView

IMPLEMENT_DYNCREATE(CAnalyticDrawingView, CView)

BEGIN_MESSAGE_MAP(CAnalyticDrawingView, CView)
	// Standard printing commands
	ON_COMMAND(ID_FILE_PRINT, &CView::OnFilePrint)
	ON_COMMAND(ID_FILE_PRINT_DIRECT, &CView::OnFilePrint)
	ON_COMMAND(ID_FILE_PRINT_PREVIEW, &CAnalyticDrawingView::OnFilePrintPreview)
//	ON_WM_CONTEXTMENU()
//	ON_WM_RBUTTONUP()
	ON_WM_CREATE()
	ON_WM_DESTROY()
	ON_WM_SIZE()
	ON_WM_RBUTTONDOWN()
	ON_WM_RBUTTONUP()
	ON_WM_MOUSEWHEEL()
	ON_WM_MOUSEMOVE()
//	ON_WM_TIMER()
ON_WM_LBUTTONDOWN()
ON_WM_LBUTTONUP()
ON_WM_LBUTTONDBLCLK()
ON_WM_RBUTTONDBLCLK()
END_MESSAGE_MAP()

// CAnalyticDrawingView construction/destruction

CAnalyticDrawingView::CAnalyticDrawingView()
	: m_pDC(NULL), m_pDisplay(NULL)
{
	// TODO: add construction code here

}

CAnalyticDrawingView::~CAnalyticDrawingView()
{
	if (m_pDC)
	{
		delete m_pDC;
		m_pDC = NULL;
	}
	if (m_pDisplay)
	{
		delete m_pDisplay;
		m_pDisplay = NULL;
	}

}

BOOL CAnalyticDrawingView::PreCreateWindow(CREATESTRUCT& cs)
{
	// TODO: Modify the Window class or styles here by modifying
	//  the CREATESTRUCT cs

	return CView::PreCreateWindow(cs);
}

// CAnalyticDrawingView drawing

void CAnalyticDrawingView::OnDraw(CDC* /*pDC*/)
{
	CAnalyticDrawingDoc* pDoc = GetDocument();
	ASSERT_VALID(pDoc);
	if (!pDoc)
		return;

	// TODO: add draw code for native data here
	glClearColor(0.9, 0.9, 0.9, 1.0);
	glClearDepth(1.0);
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
	glShadeModel(GL_SMOOTH);
	m_pDisplay->GetCamera()->ChangeViewPoint(0, 0, 0);

// 	//m_pDisplay->InitRenderParas();
// 
 	CMainFrame *pMainFrame = (CMainFrame *)(CView::GetParentFrame());
 	m_pDisplay->RenderScene(!pMainFrame->IsViewRenderClicked());
	SwapBuffers(wglGetCurrentDC());
}

// CAnalyticDrawingView printing

void CAnalyticDrawingView::OnFilePrintPreview()
{
#ifndef SHARED_HANDLERS
	AFXPrintPreview(this);
#endif
}

BOOL CAnalyticDrawingView::OnPreparePrinting(CPrintInfo* pInfo)
{
	// default preparation
	return DoPreparePrinting(pInfo);
}

void CAnalyticDrawingView::OnBeginPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/)
{
	// TODO: add extra initialization before printing
}

void CAnalyticDrawingView::OnEndPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/)
{
	// TODO: add cleanup after printing
}

//void CAnalyticDrawingView::OnRButtonUp(UINT /* nFlags */, CPoint point)
//{
//	ClientToScreen(&point);
//	OnContextMenu(this, point);
//}

//void CAnalyticDrawingView::OnContextMenu(CWnd* /* pWnd */, CPoint point)
//{
//#ifndef SHARED_HANDLERS
//	theApp.GetContextMenuManager()->ShowPopupMenu(IDR_POPUP_EDIT, point.x, point.y, this, TRUE);
//#endif
//}


// CAnalyticDrawingView diagnostics

#ifdef _DEBUG
void CAnalyticDrawingView::AssertValid() const
{
	CView::AssertValid();
}

void CAnalyticDrawingView::Dump(CDumpContext& dc) const
{
	CView::Dump(dc);
}

CAnalyticDrawingDoc* CAnalyticDrawingView::GetDocument() const // non-debug version is inline
{
	ASSERT(m_pDocument->IsKindOf(RUNTIME_CLASS(CAnalyticDrawingDoc)));
	return (CAnalyticDrawingDoc*)m_pDocument;
}
#endif //_DEBUG


// CAnalyticDrawingView message handlers


int CAnalyticDrawingView::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
	if (CView::OnCreate(lpCreateStruct) == -1)
		return -1;

	// TODO:  Add your specialized creation code here

	m_pDisplay = new COpenGLDisplay(this);
	ASSERT(m_pDisplay != NULL);
	//m_pDisplay->InitRenderParas();

	CCamera* pCamera = m_pDisplay->GetCamera();
	CAnalyticDrawingDoc* pDoc = GetDocument();
	CSketchModel* pModel = pDoc->GetSketchModel();
	pModel->SetCamera(pCamera);
	pModel->Init();

	m_pDC = new CClientDC(this);
	ASSERT(m_pDC != NULL);

	if (!bSetDCPixelFormat()) return -1;

	m_hRC = wglCreateContext(m_pDC->GetSafeHdc());
	wglMakeCurrent(m_pDC->GetSafeHdc(), m_hRC);

	return 0;
}


void CAnalyticDrawingView::OnDestroy()
{
	CView::OnDestroy();

	// TODO: Add your message handler code here
	wglMakeCurrent(NULL, NULL);
	wglDeleteContext(m_hRC);
	delete m_pDC;
	m_pDC = NULL;
}

void CAnalyticDrawingView::OnSize(UINT nType, int cx, int cy)
{
	CView::OnSize(nType, cx, cy);

	// TODO: Add your message handler code here
// 	m_pDisplay->InitRenderParas();
// 
// 
 	CCamera* pCamera = m_pDisplay->GetCamera();

 	pCamera->SetViewPort(cx, cy);
 	double hAngle = 45;
 	double zNear = 10, zFar = 125;
 	pCamera->SetPerspectiveParas(hAngle, cx * 1.0 / cy, zNear, zFar);
 	pCamera->ChangeViewPoint(0, 0, 0);
	GetDocument()->GetSketchModel()->UpdateVertices2D();

}

BOOL CAnalyticDrawingView::bSetDCPixelFormat(void)
{
	static PIXELFORMATDESCRIPTOR pfd = 
	{
		sizeof(PIXELFORMATDESCRIPTOR),
		1,
		PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER,
		PFD_TYPE_RGBA,
		32,
		0, 0, 0, 0, 0, 0,
		0, 0,
		0, 0, 0, 0, 0,
		16,
		0, 0, 0, 0, 0, 0, 0
	};

	int nPixelFormat = ChoosePixelFormat(m_pDC->GetSafeHdc(), &pfd);
	if (nPixelFormat == 0)
		return false;
	return SetPixelFormat(m_pDC->GetSafeHdc(), nPixelFormat, &pfd);
}

void CAnalyticDrawingView::OnInitialUpdate()
{
	CView::OnInitialUpdate();

	// TODO: Add your specialized code here and/or call the base class
	//glClearColor(0.0, 0.0, 0.0, 1.0);
}


void CAnalyticDrawingView::OnRButtonDown(UINT nFlags, CPoint point)
{
	// TODO: Add your message handler code here and/or call default

	CSketchModel* pModel = GetDocument()->GetSketchModel();
	CRect rect;
	GetClientRect(&rect);
	CVertex2D pVertex2D;
	pVertex2D.SetValue(point.x, rect.Height() - point.y - 1);
	CVertex *pVertex = pModel->GetActiveVertex();
	if (pVertex && CalcDistance(pVertex->m_v2D, pVertex2D) < SKE_ERROR_POINT)
	{
		m_mouse.SetActiveVertexState(true);
		pModel->InferActivePoint(pVertex2D);
		InvalidateRect(NULL, FALSE);
	}
	else
	{
		m_mouse.SetActiveVertexState(false);
		UINT nPreFlages = m_mouse.GetFlag();
		if (nPreFlages & MK_RBUTTON)
		{
			CPoint prePoint = m_mouse.GetPoint();
			m_pDisplay->GetCamera()->ChangeViewPoint((point - prePoint).cx, (point - prePoint).cy, 0);
			GetDocument()->GetSketchModel()->UpdateVertices2D();
		}
	}
	m_mouse.SetFlag(nFlags);
	m_mouse.SetPoint(point);
	CView::OnRButtonDown(nFlags, point);
}


void CAnalyticDrawingView::OnRButtonUp(UINT nFlags, CPoint point)
{
	// TODO: Add your message handler code here and/or call default

	if (m_mouse.GetActiveVertexState())
	{
		m_mouse.SetActiveVertexState(false);
		//	infer new line segment here!
		
	}
	m_mouse.SetFlag(nFlags);
	m_mouse.SetPoint(point);
	CView::OnRButtonUp(nFlags, point);
}


BOOL CAnalyticDrawingView::OnMouseWheel(UINT nFlags, short zDelta, CPoint pt)
{
	// TODO: Add your message handler code here and/or call default
	if (zDelta)
	{	
		m_pDisplay->GetCamera()->ChangeViewPoint(0, 0, zDelta);
		GetDocument()->GetSketchModel()->UpdateVertices2D();
		InvalidateRect(NULL, FALSE);
	}
	m_mouse.SetFlag(nFlags);
	m_mouse.SetPoint(pt);
	m_mouse.SetWheelAngle(zDelta);
	return CView::OnMouseWheel(nFlags, zDelta, pt);
}

void CAnalyticDrawingView::OnMouseMove(UINT nFlags, CPoint point)
{
	// TODO: Add your message handler code here and/or call default

	UINT nPreFlages = m_mouse.GetFlag();
	if (nPreFlages & MK_RBUTTON)
	{
		//	when you move the mouse with right button pressed
		//	it will either change the viewpoint, or change the active vertex
		//	depending on the state of active vertex
		if (!m_mouse.GetActiveVertexState())
		{
			//	if the state for active vertex is inactive
			//	then we try to change the viewpoint
			CPoint prePoint = m_mouse.GetPoint();
			CSize difVector = point - prePoint;
			if (difVector.cx || difVector.cy)
			{
				m_pDisplay->GetCamera()->ChangeViewPoint(difVector.cy, difVector.cx, 0);
				GetDocument()->GetSketchModel()->UpdateVertices2D();
				InvalidateRect(NULL, FALSE);
			}
		}
		else
		{
			CSketchModel* pModel = GetDocument()->GetSketchModel();
			CRect rect;
			GetClientRect(&rect);
			CVertex2D pVertex2D;
			pVertex2D.SetValue(point.x, rect.Height() - point.y - 1);
			CVertex *pVertex = pModel->GetActiveVertex();
			if (pVertex)
			{
				m_mouse.SetActiveVertexState(true);
				pModel->InferActivePoint(pVertex2D);
				InvalidateRect(NULL, FALSE);
			}
		}
	}
	else if (nPreFlages & MK_LBUTTON)
	{
		CRect rect;
		GetClientRect(&rect);
		CVertex2D pVertex;
		pVertex.SetValue(point.x, rect.Height() - point.y - 1);
		m_pDisplay->GetStrokeManager()->AddPoint(pVertex);
		InvalidateRect(NULL, FALSE);
	}
	m_mouse.SetFlag(nFlags);
	m_mouse.SetPoint(point);
	CView::OnMouseMove(nFlags, point);
}


void CAnalyticDrawingView::OnLButtonDown(UINT nFlags, CPoint point)
{
	// TODO: Add your message handler code here and/or call default
	m_pDisplay->GetStrokeManager()->ClearStroke();

	m_mouse.SetFlag(nFlags);
	m_mouse.SetPoint(point);
	CView::OnLButtonDown(nFlags, point);
}


void CAnalyticDrawingView::OnLButtonUp(UINT nFlags, CPoint point)
{
	// TODO: Add your message handler code here and/or call default

	//	infer the stroke here
	if (m_pDisplay->GetStrokeManager()->GetStrokeLength() > SKE_MIN_STROKE_LENGTH)
	{
		bool isLine = m_pDisplay->GetStrokeManager()->IsLine();
		CSketchModel* pModel = GetDocument()->GetSketchModel();
		pModel->SetStrokes(*m_pDisplay->GetStrokeManager());
		if (isLine)
		{
			if (!pModel->InferScaffold())
				pModel->InferLine();
		}
		else
		{
			pModel->InferCurve();
		}
		m_pDisplay->GetStrokeManager()->ClearStroke();
		InvalidateRect(NULL, FALSE);

		pModel->InferSurface(m_pDisplay->GetSketchPaint()->GetCurveSegment());

		CMainFrame *pMainFrame = (CMainFrame *)(CView::GetParentFrame());
		pMainFrame->UpdateStatusBar(pModel->GetVertexCountWithoutInfPoint(), pModel->GetLineSegmentCount(), pModel->GetScaffoldCount(),
			pModel->GetCurveCount(), pModel->GetSurfaceCount());
	}

	m_mouse.SetFlag(nFlags);
	m_mouse.SetPoint(point);
	CView::OnLButtonUp(nFlags, point);
}

void CAnalyticDrawingView::OnLButtonDblClk(UINT nFlags, CPoint point)
{
	// TODO: Add your message handler code here and/or call default
	CSketchModel* pModel = GetDocument()->GetSketchModel();
	CRect rect;
	GetClientRect(&rect);
	CVertex2D pVertex;
	pVertex.SetValue(point.x, rect.Height() - point.y - 1);
	pModel->GetVertexManager()->AddVertex(pModel->InferPoint(pVertex));
	InvalidateRect(NULL, FALSE);
	
	CMainFrame *pMainFrame = (CMainFrame *)(CView::GetParentFrame());
	pMainFrame->UpdateStatusBar(pModel->GetVertexCountWithoutInfPoint(), pModel->GetLineSegmentCount(), pModel->GetScaffoldCount(),
		pModel->GetCurveCount(), pModel->GetSurfaceCount());

	m_mouse.SetFlag(nFlags);
	m_mouse.SetPoint(point);
	CView::OnLButtonDblClk(nFlags, point);
}

void CAnalyticDrawingView::OnRButtonDblClk(UINT nFlags, CPoint point)
{
	// TODO: Add your message handler code here and/or call default
	CSketchModel* pModel = GetDocument()->GetSketchModel();
	CRect rect;
	GetClientRect(&rect);
	CVertex2D pVertex2D;
	pVertex2D.SetValue(point.x, rect.Height() - point.y - 1);
	CVertex* pVertex = pModel->GetVertexManager()->FindNearest2DVertex(pVertex2D);
	if (CalcDistance(pVertex2D, pVertex->m_v2D) < SKE_ERROR_POINT)
		pModel->SetActiveVertex(pVertex);
	else
		pModel->SetActiveVertex(NULL);
	InvalidateRect(NULL, FALSE);

	m_mouse.SetFlag(nFlags);
	m_mouse.SetPoint(point);
	CView::OnRButtonDblClk(nFlags, point);
}
